package ir;

import java.util.ArrayList;
import java.util.List;

import run.Bind;
import run.Cell;
import run.Facet;
import run.Lattice;

/**
 * A structural definition is an Intermediate Representation class which
 * maintains a "blue print", the definition, for a cell's internal structure.
 * Realizing the structure will produce a Lattice, which encodes
 * the structure of the cell. 
 * 
 * @author Thomas Chau
 *
 */
public class StructuralDefinition {
	
	/* Statements */
	public ArrayList<Stmt> statements;
	
	// Facets for this structure
	public ArrayList<Facet> ourFacets;
	// Cell of this structure, to be returned.
	public Cell myCell;
	
	public StructuralDefinition() {
		statements = new ArrayList<Stmt>();
		ourFacets = new ArrayList<Facet>();
	}
	
	/**
	 * Adds a statement's contribution to the structural definition.
	 * @param s
	 */
	public void add(Stmt s) {
		statements.add(s);
	}

	/** 
	 * Realizes the structural definition, prior to execution.
	 * @param name 
	 */
	public Cell realize(String name) {
		Lattice lat = new Lattice(name);
		myCell = new Cell(name, lat);
		
		for (Stmt s : statements)
			s.preFilter();
		
		// Retrieve the decomposed binds for each Statement.
		for(Stmt s : statements) {
			ArrayList<run.Bind> binds = s.getBinds(this);
			for (Bind b : binds) {
				lat.addBind(b);
			}
		}
		
		// REALIZE: here or in Stimulate()??????? broke.
		myCell.realize();
		return myCell;
	}

	/**
	 * In its symbolTable-like role, the definition will search and retrieve the
	 * CellUnit identified by this label.
	 * @param labelName
	 */
	public CellUnit findInstance(String labelName) {
		for (Stmt s : statements) {
			CellUnit candidate = s.findInstance(labelName);
			if (candidate != null)
				return (CellUnit) candidate;
		}
		return null;
	}
	
	/**
	 * Retrieves a Facet reference.
	 * If no such Facet exists already, constructs a new one and
	 * associates it with the Cell we are building.
	 * @param name
	 * @return
	 */
	public Facet getFacet(String name, boolean isInputFacet) {
		Facet newFacet;
		for (Facet f : ourFacets)
			if (f.getName().equals(name))
				return f;

		newFacet = new Facet(name, myCell, isInputFacet);
		ourFacets.add(newFacet);
		
		return newFacet;
	}
	
	public StructuralDefinition clone() {
		StructuralDefinition newDef = new StructuralDefinition();
		for (Stmt s : statements)
			newDef.add(s.clone());
		return newDef;
	}
}